﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using MediaStreamer.Containers;
using Org.Flowertwig.Media;
using Org.Flowertwig.Media.Information;
using Org.Flowertwig.Media.Information.Services;

namespace MediaStreamer.Transformers
{
    public class SerieTransformer
    {
        const string popcornhourShareName = "temp2";

        private double _prepareProcess = 0;
        private double _copyProcess = 0;

        public IEnumerable<MenuItem> Transform(string id, RequestInfo requestInfo)
        {
            var menuItems = new List<MenuItem>();

            var serie = Storage.GetDocument<Serie>(id);

            if (serie != null)
            {
                switch (requestInfo.ResourceId)
                {
                    case "/series/episode/view":
                        string episodeId = requestInfo.Query.Get("eid");
                        try
                        {
                            using (var session = Storage.DocumentStore.OpenSession())
                            {
                                var result = session.Query<Media>().Where(m => m.InformationId == episodeId);

                                // TODO: Add functionality to handle more then 1 media for a episode.

                                var first = result.FirstOrDefault();
                                if (first != null)
                                {
                                    var service = session.Query<Service>().FirstOrDefault(s => s.Id == first.ServiceId);
                                    // TODO: What todo IF we don't find serivce?
                                    if (service != null)
                                    {
                                        if (first.RequireProcessBeforePlay)
                                        {

                                            var prepareMenuItems = PrepareMedia(first, service);
                                            if (prepareMenuItems != null && prepareMenuItems.Count >= 0)
                                            {
                                                menuItems.AddRange(prepareMenuItems);
                                            }
                                        }else
                                        {
                                            // Media doesn't need to be prepared
                                            var prepareMenuItems = CopyMedia(first, service);
                                            if (prepareMenuItems != null && prepareMenuItems.Count >= 0)
                                            {
                                                menuItems.AddRange(prepareMenuItems);
                                            }
                                        }
                                    }

                                }
                            }
                        }
                        catch (Exception exception)
                        {
                            // TODO: Add better exception handling here ;)
                        }
                        break;
                    case "/series/season/view":
                        var sn = requestInfo.Query.Get("sn");
                        int seasonNumber;
                        if (!int.TryParse(sn, out seasonNumber))
                        {
                            seasonNumber = 0;
                        }

                        var currentSeason = serie.Seasons.FirstOrDefault(s => s.Number == seasonNumber);
                        if (currentSeason != null)
                        {
                            menuItems.Add(new MenuItem
                                              {
                                                  ElementId = "IntroHeader",
                                                  Text = string.Format("Season {0:00}", currentSeason.Number)
                                              });

                            foreach (var episode in currentSeason.Episodes)
                            {
                                menuItems.Add(new MenuItem
                                                  {
                                                      Text = episode.Name,
                                                      NavigateToLocation = string.Format("/series/episode/view?id={0}&type=serie&sn={1}&eid={2}", id, seasonNumber, episode.Id),
                                                      SortIndex = episode.Number,
                                                      ElementId = "List"
                                                  });
                            }
                        }

                        foreach (var season in serie.Seasons)
                        {
                            menuItems.Add(new MenuItem
                            {
                                ElementId = "CompactSeasons",
                                Text = string.Format("{0:00}", season.Number),
                                NavigateToLocation = string.Format("/series/season/view?id={0}&type=serie&sn={1}", id, season.Number)
                            });
                        }

                        menuItems.Add(new MenuItem
                        {
                            ElementId = "HeaderImage",
                            NavigateToLocation = serie.ImageSrc,
                            Text = serie.Name
                        });

                        break;
                    case "/series/view":
                        foreach (var season in serie.Seasons)
                        {
                            menuItems.Add(new MenuItem
                                              {
                                                  ElementId = "CompactSeasons",
                                                  Text = string.Format("{0:00}", season.Number),
                                                  NavigateToLocation = string.Format("/series/season/view?id={0}&type=serie&sn={1}", id, season.Number)
                                              });
                        }

                        menuItems.Add(new MenuItem
                        {
                            ElementId = "HeaderImage",
                            NavigateToLocation = serie.ImageSrc,
                            Text = serie.Name
                        });

                        var summaryLines = serie.Summary.Split(new[] { '\r', '\n' });
                        int summaryIndex = 0;
                        foreach (var line in summaryLines)
                        {
                            menuItems.Add(new MenuItem
                            {
                                ElementId = "Intro",
                                Text = line,
                                SortIndex = summaryIndex
                            });
                            summaryIndex++;
                        }

                        // This has to be after "Intro"
                        menuItems.Add(new MenuItem
                        {
                            ElementId = "IntroHeader",
                            Text = serie.Name
                        });
                        break;
                }



            }
            return menuItems;
        }

        private IList<MenuItem> CopyMedia(Media first, Service service)
        {
            IList<MenuItem> menuItems = new List<MenuItem>();
            var process = new Process();
            var startInfo =
                new ProcessStartInfo(service.ApplicationPathAndName,
                                     string.Format("/copy:{0}",
                                                   first.InternalServiceId))
                {
                    RedirectStandardInput = true,
                    RedirectStandardOutput = true,
                    UseShellExecute = false
                };
            process.OutputDataReceived += copyOutputDataReceived;
            process.StartInfo = startInfo;

            process.Start();

            _copyProcess = -1;

            // Start the asynchronous read of the sort output stream.
            process.BeginOutputReadLine();
            //process.WaitForExit();

            // Sleep until we have a response but don't wait until the copy process is finished
            do
            {
                System.Threading.Thread.Sleep(100);
            } while (_copyProcess == -1);

            if (_copyProcess < 100)
            {
                menuItems.Add(new MenuItem
                {
                    ElementId = "List",
                    Text =
                        string.Format(
                            "Preparing file. {0:0}% complete.",
                            _copyProcess)
                });

                // This post will tell page to refresh it self after 10 sec.
                menuItems.Add(new MenuItem
                {
                    ElementId = "MetaAutoRefreshPage",
                    NavigateToLocation = "{CURRENTURL}",
                    Text = "10"
                });
            }
            else
            {
                var internalId = Hash.CreateId(first.InternalServiceId);
                var navigationLocation =
                    string.Format(
                        "http://localhost.drives:8883/NETWORK_SHARE/{1}/{0}/?filter=3",
                        internalId, popcornhourShareName);

                menuItems.Add(new MenuItem
                {
                    ElementId = "List",
                    Text =
                        "Files has been prepared and copied to output path.",
                    SortIndex = 0
                    /*,
                              NavigateToLocation = navigationLocation*/
                });

                menuItems.Add(new MenuItem
                {
                    ElementId = "List",
                    Text = "Click here to open files, or wait 10 sec",
                    NavigateToLocation = navigationLocation,
                    SortIndex = 711
                });

                // This post will tell page to refresh it self after 10 sec.
                menuItems.Add(new MenuItem
                {
                    ElementId = "MetaAutoRefreshPage",
                    NavigateToLocation = navigationLocation,
                    Text = "10"
                });
            }
            return menuItems;
        }

        private IList<MenuItem> PrepareMedia(Media first, Service service)
        {
            IList<MenuItem> menuItems = new List<MenuItem>();
            var process = new Process();
            var startInfo =
                new ProcessStartInfo(service.ApplicationPathAndName,
                                     string.Format("/prepare:{0}",
                                                   first.InternalServiceId))
                    {
                        RedirectStandardInput = true,
                        RedirectStandardOutput = true,
                        UseShellExecute = false
                    };
            process.OutputDataReceived += prepareOutputDataReceived;
            process.StartInfo = startInfo;

            process.Start();

            // Start the asynchronous read of the sort output stream.
            process.BeginOutputReadLine();
            process.WaitForExit();

            if (_prepareProcess < 100)
            {
                menuItems.Add(new MenuItem
                                  {
                                      ElementId = "List",
                                      Text =
                                          string.Format(
                                              "Preparing file. {0:0}% complete.",
                                              _prepareProcess)
                                  });

                // This post will tell page to refresh it self after 10 sec.
                menuItems.Add(new MenuItem
                                  {
                                      ElementId = "MetaAutoRefreshPage",
                                      NavigateToLocation = "{CURRENTURL}",
                                      Text = "10"
                                  });
            }
            else
            {
                var internalId = Hash.CreateId(first.InternalServiceId);
                var navigationLocation =
                    string.Format(
                        "http://localhost.drives:8883/NETWORK_SHARE/{1}/{0}/?filter=3",
                        internalId, popcornhourShareName);

                menuItems.Add(new MenuItem
                                  {
                                      ElementId = "List",
                                      Text =
                                          "Files has been prepared and copied to output path.",
                                      SortIndex = 0
                                      /*,
                                                NavigateToLocation = navigationLocation*/
                                  });

                menuItems.Add(new MenuItem
                                  {
                                      ElementId = "List",
                                      Text = "Click here to open files, or wait 10 sec",
                                      NavigateToLocation = navigationLocation,
                                      SortIndex = 711
                                  });

                // This post will tell page to refresh it self after 10 sec.
                menuItems.Add(new MenuItem
                                  {
                                      ElementId = "MetaAutoRefreshPage",
                                      NavigateToLocation = navigationLocation,
                                      Text = "10"
                                  });
            }
            return menuItems;
        }

        void prepareOutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            const string processStatusText = "PROCESS:";

            if (!string.IsNullOrEmpty(e.Data) && e.Data.StartsWith(processStatusText))
            {
                Console.WriteLine("# Program >" + e.Data);

                var value = e.Data.Substring(processStatusText.Length);
                double tmp;
                if (double.TryParse(value, out tmp))
                {
                    _prepareProcess = tmp;
                }
            }else
            {
                Console.WriteLine("# Program(Unhandled) >" + e.Data);
            }
        }

        void copyOutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            const string processStatusText = "PROCESS:";

            if (!string.IsNullOrEmpty(e.Data) && e.Data.StartsWith(processStatusText))
            {
                Console.WriteLine("# Program >" + e.Data);

                var value = e.Data.Substring(processStatusText.Length);
                double tmp;
                if (double.TryParse(value, out tmp))
                {
                    _prepareProcess = tmp;
                }
            }
            else
            {
                Console.WriteLine("# Program(Unhandled) >" + e.Data);
            }
        }
    }
}
